package com.resume.aipeople.service.ai.asr;

import com.baidu.aip.speech.AipSpeech;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 百度语音识别策略实现
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class BaiduSpeechRecognitionStrategy implements SpeechRecognitionStrategy {
    
    private final AipSpeech aipSpeech;
    
    @Value("${baidu.voice.api.key:your-baidu-api-key}")
    private String baiduApiKey;
    
    @Value("${baidu.voice.secret.key:your-baidu-secret-key}")
    private String baiduSecretKey;
    
    @Override
    public String getStrategyName() {
        return "baidu";
    }
    
    @Override
    public String getDisplayName() {
        return "百度语音识别";
    }
    
    @Override
    public boolean isAvailable() {
        return !baiduApiKey.equals("your-baidu-api-key") && 
               !baiduSecretKey.equals("your-baidu-secret-key");
    }
    
    @Override
    public Mono<String> speechToText(MultipartFile audioFile) {
        return Mono.fromCallable(() -> {
            try {
                if (!isAvailable()) {
                    log.info("百度语音API未配置，使用模拟ASR");
                    return mockSpeechToText(audioFile);
                }
                
                // 获取音频文件数据
                byte[] audioData = audioFile.getBytes();
                String format = detectAudioFormat(audioFile);
                int sampleRate = detectSampleRate(audioData, format);
                
                log.info("百度ASR - 音频文件信息: 格式={}, 大小={}KB, 采样率={}", 
                        format, audioData.length/1024, sampleRate);
                
                // 设置识别参数
                HashMap<String, Object> options = new HashMap<>();
                options.put("cuid", "aipeople_" + System.currentTimeMillis());
                options.put("dev_pid", 1537); // 普通话(纯中文识别) 语音近场识别模型
                
                log.debug("百度ASR参数: format={}, rate={}, cuid={}, dev_pid={}", 
                         format, sampleRate, options.get("cuid"), options.get("dev_pid"));
                
                // 多模型尝试：提升识别稳定性
                int[] devPidCandidates = new int[]{1537, 1536, 1936};
                List<String> candidateResults = new ArrayList<>();
                
                for (int devPid : devPidCandidates) {
                    options.put("dev_pid", devPid);
                    String result = recognizeOnce(audioData, format, sampleRate, options);
                    if (result != null && !result.isBlank()) {
                        candidateResults.add(result);
                        log.info("百度ASR候选(dev_pid={}): {}", devPid, result);
                    }
                }
                
                String best = pickBestRecognition(candidateResults);
                if (best != null && !best.trim().isEmpty()) {
                    String normalized = normalizeDigits(best);
                    log.info("百度ASR最终结果: {} -> 规范化: {}", best, normalized);
                    return normalized;
                }
                
                // 如果所有模型都失败，尝试不同的音频格式
                log.warn("所有百度ASR模型都失败，尝试格式转换");
                String convertedFormat = tryFormatConversion(audioData, format);
                if (!convertedFormat.equals(format)) {
                    log.info("尝试转换格式: {} -> {}", format, convertedFormat);
                    String convertedResult = recognizeOnce(audioData, convertedFormat, sampleRate, options);
                    if (convertedResult != null && !convertedResult.trim().isEmpty()) {
                        log.info("格式转换后识别成功: {}", convertedResult);
                        return normalizeDigits(convertedResult);
                    }
                }
                
                log.error("百度语音识别完全失败，返回空结果");
                return "";
                
            } catch (Exception e) {
                log.error("百度语音识别异常", e);
                return mockSpeechToText(audioFile);
            }
        })
        .doOnError(error -> log.error("百度语音识别调用失败", error))
        .onErrorReturn(mockSpeechToText(audioFile));
    }
    
    /**
     * 单次识别调用并解析
     */
    private String recognizeOnce(byte[] audioData, String format, int sampleRate, HashMap<String, Object> options) {
        try {
            JSONObject result = aipSpeech.asr(audioData, format, sampleRate, options);
            log.info("百度ASR响应: {}", result.toString());
            if (result.has("err_no") && result.getInt("err_no") == 0) {
                if (result.has("result") && result.getJSONArray("result").length() > 0) {
                    return result.getJSONArray("result").getString(0);
                }
                return null;
            } else {
                int errorCode = result.optInt("err_no");
                String errorMsg = result.optString("err_msg", "未知错误");
                log.warn("百度ASR识别失败: {} (错误码: {})", errorMsg, errorCode);
                return null;
            }
        } catch (Exception e) {
            log.warn("百度ASR识别异常: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 选择最优识别结果
     */
    private String pickBestRecognition(List<String> candidates) {
        if (candidates == null || candidates.isEmpty()) return null;
        String best = null;
        int bestScore = Integer.MIN_VALUE;
        for (String s : candidates) {
            int score = scoreForDigits(s) - profanityPenalty(s);
            if (score > bestScore) { 
                bestScore = score; 
                best = s; 
            }
        }
        return best != null ? best.trim() : candidates.get(0).trim();
    }
    
    private int scoreForDigits(String s) {
        if (s == null) return 0;
        int digits = (int) s.chars().filter(ch -> Character.isDigit(ch)).count();
        int cnDigits = (int) s.chars().filter(ch -> "〇零一二三四五六七八九十百千两幺壹贰叁肆伍陆柒捌玖拾".indexOf(ch) >= 0).count();
        int len = Math.max(1, s.length());
        return (digits + cnDigits) * 4 - (len - (digits + cnDigits));
    }
    
    private int profanityPenalty(String s) {
        if (s == null) return 0;
        String[] bad = new String[]{"操你", "傻逼", "妈的"};
        for (String b : bad) if (s.contains(b)) return 8;
        return 0;
    }
    
    /**
     * 将常见口语数字规范化
     */
    private String normalizeDigits(String s) {
        if (s == null) return null;
        String t = s;
        t = t.replace("幺", "一");
        t = t.replace("两", "二");
        t = t.replace("壹", "一").replace("贰", "二").replace("叁", "三").replace("肆", "四")
             .replace("伍", "五").replace("陆", "六").replace("柒", "七").replace("捌", "八")
             .replace("玖", "九").replace("拾", "十");
        return t;
    }
    
    /**
     * 尝试格式转换
     */
    private String tryFormatConversion(byte[] audioData, String currentFormat) {
        if ("pcm".equals(currentFormat)) {
            log.info("PCM格式识别失败，尝试WAV格式");
            return "wav";
        }
        
        if ("wav".equals(currentFormat)) {
            log.info("WAV格式识别失败，尝试PCM格式");
            return "pcm";
        }
        
        log.info("{}格式识别失败，尝试PCM格式", currentFormat);
        return "pcm";
    }
    
    private String mockSpeechToText(MultipartFile audioFile) {
        String filename = audioFile.getOriginalFilename();
        return "这是百度模拟的语音识别结果，文件名: " + filename;
    }
}



